/*******************************************************************************
 * Copyright (c) 2006 CEA List.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     CEA List - initial API and implementation
 *******************************************************************************/
package com.cea.papyrus.tabbedproperties.section;

import org.eclipse.core.runtime.Assert;
import org.eclipse.gef.editparts.AbstractGraphicalEditPart;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;
import org.eclipse.uml2.uml.Constraint;

import com.cea.papyrus.core.PapyrusPlugin;
import com.cea.papyrus.core.preference.CommonPreferenceConstants;
import com.cea.papyrus.core.tabbedproperties.PropertyViewSection;
import com.cea.papyrus.core.utils.Debug;
import com.cea.papyrus.diagraminterchange2.di2.Di2Factory;
import com.cea.papyrus.diagraminterchange2.di2.GraphElement;
import com.cea.papyrus.umlutils.ICustomAppearence;

/**
 * Section for constraint Appearance 
 */
public class ConstraintAppearanceSection extends PropertyViewSection {

	private static final int PREFERED_GROUP_WIDTH = 100;

	/** graph element on which properties are displayed */
	private GraphElement graphElement;

	/** Check boxes for operation */
	private Button displBody, displName;
	
	/**  group that contains check boxes */
	protected Group operationGroup;

	/** Buttons listeners */
	private SelectionListener displNameListener, displBodyListener;

	/**
	 * 
	 * 
	 * @param tabbedPropertySheetPage 
	 * @param parent 
	 */
	@Override
	public void createControls(Composite parent, TabbedPropertySheetPage tabbedPropertySheetPage) {
		super.createControls(parent, tabbedPropertySheetPage);
		Composite composite = getWidgetFactory().createFlatFormComposite(parent);
		createConstraintGroup(composite);
	}

	/**
	 * Create the group 
	 * @param composite
	 */
	private void createConstraintGroup(Composite composite) {
		// create group
		operationGroup = getWidgetFactory().createGroup(composite, "Constraint");
		FormLayout layout = new FormLayout();
		operationGroup.setLayout(layout);
		FormData data;

		// create check buttons in this group
		displName = getWidgetFactory().createButton(operationGroup, "Name", SWT.CHECK);
		data = new FormData();
		data.top = new FormAttachment(0, 0);
		data.left = new FormAttachment(0, 0);
		displName.setLayoutData(data);
		displName.addSelectionListener(displNameListener = new AppearenceSelectionListener(ICustomAppearence.DISP_NAME));

		displBody = getWidgetFactory().createButton(operationGroup, "Body", SWT.CHECK);
		data = new FormData();
		data.left = new FormAttachment(0, 0);
		data.top = new FormAttachment(displName, 0);
		displBody.setLayoutData(data);
		displBody.addSelectionListener(displBodyListener = new AppearenceSelectionListener(ICustomAppearence.DISP_BODY));
		
		data = new FormData();
		data.left = new FormAttachment(0, 0);
		data.top = new FormAttachment(0, 0);
		data.width = Math.max(PREFERED_GROUP_WIDTH, displBody.computeSize(SWT.DEFAULT, SWT.DEFAULT).x);
		operationGroup.setLayoutData(data);
	}

	/* (non-Javadoc)
	 * @see org.eclipse.ui.views.properties.tabbed.AbstractPropertySection#refresh()
	 */
	@Override
	public void refresh() {
		if(isButtonValid(displBody)){
			IPreferenceStore store = PapyrusPlugin.getDefault().getPreferenceStore();
			int style = 0;

			// get properties on graph node for property: custom display
			com.cea.papyrus.diagraminterchange2.di2.Property prop = graphElement.getProperty(ICustomAppearence.CUSTOM_APPEARENCE_KEY);
			String value = "";
			if(prop == null) {
				// default value 
				style = loadPreferenceStyle(store);
			} else {
				value = prop.getValue();
				if(value != null) {
					try {
						style = Integer.parseInt(value);
					} catch (NumberFormatException e) {
						Debug.log(e);
					}
				}
			}

			if(this.getElement() instanceof Constraint) {
				displBody.setSelection((style & ICustomAppearence.DISP_BODY) != 0);
				displName.setSelection((style & ICustomAppearence.DISP_NAME) != 0);
			}
		}
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.ui.properties.tabbed.PropertyViewSection#setInput(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
	 */
	public void setInput(IWorkbenchPart part, ISelection selection) {
		super.setInput(part, selection);
		Assert.isTrue(selection instanceof IStructuredSelection);
		Object input = ((IStructuredSelection) selection).getFirstElement();

		if(input instanceof AbstractGraphicalEditPart) {
			graphElement = ((GraphElement)((AbstractGraphicalEditPart) input).getModel());
		} else {
			graphElement = null;
		}
		refresh();
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.ui.properties.tabbed.PropertyViewSection#dispose()
	 */
	@Override
	public void dispose(){
		// operation button disposal
		if(isButtonValid(displBody)) {
			displBody.removeSelectionListener(displBodyListener);
		}
		if(isButtonValid(displName)) {
			displName.removeSelectionListener(displNameListener);
		}
		super.dispose();
	}

	/**
	 * Returns default display from preference store
	 * @param store the preference store
	 * @return default display from preference store
	 */
	private int loadPreferenceStyle(IPreferenceStore store) {
		int style = 0;

		if (CommonPreferenceConstants.getPreferenceConstraintNameAppearance(store)){
			style = style | ICustomAppearence.DISP_NAME;
		}
		if (CommonPreferenceConstants.getPreferenceConstraintBodyAppearance(store)){
			style = style | ICustomAppearence.DISP_BODY;
		}
		return style;
	}

	/**
	 * 
	 */
	private class AppearenceSelectionListener implements SelectionListener {

		/**
		 * the constant which refers the element to display or not.
		 */
		private int style;

		/**
		 * Default Constructor.
		 * @param style 
		 */
		public AppearenceSelectionListener(int style) {
			this.style = style;
		}

		/* (non-Javadoc)
		 * @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent)
		 */
		public void widgetDefaultSelected(SelectionEvent e) {

		}

		/* (non-Javadoc)
		 * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
		 */
		public void widgetSelected(SelectionEvent e) {
			Button button = (Button)e.getSource();
			boolean isSelected = button.getSelection();

			if(graphElement == null) {
				return;
			}
			
			// default value has changed: set custom appearance property
			com.cea.papyrus.diagraminterchange2.di2.Property prop = graphElement.getProperty(ICustomAppearence.CUSTOM_APPEARENCE_KEY);
			if(prop == null) {
				prop = Di2Factory.eINSTANCE.createProperty();
				graphElement.getProperty().add(prop);
				prop.setKey(ICustomAppearence.CUSTOM_APPEARENCE_KEY);
				prop.setValue(""+loadPreferenceStyle(PapyrusPlugin.getDefault().getPreferenceStore()));
			}
			int value = Integer.parseInt(prop.getValue());

			if(isSelected) {
				if((value & style) == 0) {
					prop.setValue(""+(value | style));
				}
			} else {
				if((value & style) != 0) {
					prop.setValue(""+(value & ~style));
				}
			}
			forceToSave();
			refresh();
		}
	}

	/**
	 * returns <code>true</code> if the button is valid, i.e. not disposed and not <code>null</code>
	 * @param button the button to check
	 * @return <code>true</code> if the button is valid, i.e. not disposed and not <code>null</code>
	 */
	protected boolean isButtonValid(Button button) {
		return (button!=null && !button.isDisposed());
	}
}

